package de.dhbw.minf12.mas.mediator;

import java.util.LinkedList;
import java.util.List;

import de.dhbw.minf12.mas.Permutation;
import de.dhbw.minf12.mas.excel_export.DetailedExcelExporter;
import de.dhbw.minf12.mas.voter.AbstractVoter;
import de.dhbw.minf12.mas.voter.ConstructingVoter;

/**
 * In diesem Verfahren sollen die Agenten gemeinsam einen Vertrag konstruieren.
 * Der Mediator agiert nur als Koordinator, der die Reihenfolge der Agenten vorgibt.
 * @author flo
 *
 */
public class ConstructingMediator extends AbstractMediator {

	private List<ConstructingVoter> agentList;
	private Permutation constructionOrder;

	public ConstructingMediator(List<ConstructingVoter> agents, int numberOfContractVotes,
			int numberOfContractsInRound, DetailedExcelExporter exporter) {
		super(numberOfContractVotes, numberOfContractsInRound, exporter);
		this.agentList = agents;
		this.numberOfElementsInContract = agentList.get(0).getJobCount();
		this.numberOfAgents = agentList.size();
		this.currentContract = new Permutation(numberOfElementsInContract);
		this.currentContract.sortRandomly();
		this.constructionOrder = new Permutation(numberOfElementsInContract);
		this.constructionOrder.sortRandomly();
	}

	@Override
	public Permutation startMediation() {
		for(int i = 0; i < numberOfContractVotes; i++){
			
			int[] solutionValues = new int[3];
			int j = 0;
			for (ConstructingVoter agent: agentList) {
				solutionValues[j++] = agent.getSolutionValue(currentContract);
			}
			exporter.addRow(i, solutionValues[0], solutionValues[1]);
			//System.out.println("Current " + i + "\t\tAgent 1: " + solutionValues[0] + "\t\tAgent 2: " + solutionValues[1]);
			
			List<Integer> newContractData = new LinkedList<Integer>();
			List<Integer> jobsLeftToPlan = new Permutation(numberOfElementsInContract).getData();
			
			//Let the construction begin..
			int agentCount = agentList.size();
			for(Integer agentToConstruct : this.constructionOrder.getData()){
				Integer chosenJob = agentList.get(agentToConstruct % agentCount).vote(newContractData, jobsLeftToPlan);
				//System.out.println("Chosen Job: " + chosenJob);
				
				newContractData.add(chosenJob);
				jobsLeftToPlan.remove(chosenJob);
				
				if(jobsLeftToPlan.contains(chosenJob)){
					throw new RuntimeException("Falscher Job entfernt..");
				}
			}
			
			// check if contract is accepted by all agents
			boolean accepted = true;
			Permutation newPermutation = new Permutation(newContractData);
			for (AbstractVoter voter : agentList) {
				if(!voter.vote(newPermutation, this.currentContract)){
					accepted = false;
					break;
				}
			}
			
			if(accepted){
				this.currentContract = newPermutation;
			}
			
			//System.out.println("New " + i + "\t\tAgent 1: " + agentList.get(0).getSolutionValue(newPermutation) + "\t\tAgent 2: " + agentList.get(1).getSolutionValue(newPermutation));
			
			this.constructionOrder = this.constructionOrder.getNeighborsByShift(1).get(0);
		}
		
		return currentContract;
	}

}
